import { Vector } from "./lib/math";
import { MassPoint } from "./lib/phy";

export interface PhySystem<State> {
    state: State,
    update: (dt: number) => void,
}

export const system = <State>(
    initState: State,
    update: (state: State, dt: number) => void,
    step: number,
): PhySystem<State> => {
    let state = initState;
    let t = 0; // 与真实时间的差距
    const update_ = (dt: number) => {
        t -= dt;
        while (t < 0) {
            update(state, step);
            t += step;
        }
    };
    return { state, update: update_ };
};

export const multMassPointSystem = (
    ps: MassPoint[],
    interact: (pa: MassPoint, pb: MassPoint) => Vector,
    step: number,
    sizeX: number = Infinity,
    sizeY: number = Infinity,
) => {
    const update = (ps: MassPoint[], dt: number) => {
        for (let i = 0; i < ps.length; ++i) {
            const pa = ps[i];
            for (let j = i + 1; j < ps.length; ++j) {
                const pb = ps[j];
                const fa = interact(ps[i], ps[j]);
                pa.impluse(fa.scale(dt));
                pb.impluse(fa.scale(-dt));
            }
        }

        ps.forEach(point => point.move(dt)) // 移动
        ps.forEach(point => { // 反弹
            let { x, y } = point.p;
            let { x: vx, y: vy } = point.v;
            if (x < 0)
                x = -x, vx = -vx;
            else if (x > sizeX)
                x = sizeX - (x - sizeX), vx = -vx;
            if (y < 0)
                y = -y, vy = -vy;
            else if (y > sizeY)
                y = sizeY - (y - sizeY), vy = -vy;
            point.p = new Vector(x, y);
            point.v = new Vector(vx, vy);
        })
    }
    return system(ps, update, step);
}


export const distanceForce = (act: (len: number) => number) =>
    (pa: MassPoint, pb: MassPoint) => {
        const asb = pa.p.sub(pb.p);
        return asb.idfy(act(asb.length()));
    }
